exports.calculateKDJ = (arrClose, arrLow, arrHigh, nPeriod = 9, nKSmaPeriod = 3, nDSmaPeriod = 3)=> {
  // 参数校验
  if (!Array.isArray(arrClose) || !Array.isArray(arrLow) || !Array.isArray(arrHigh)) {
    throw new Error("输入数据必须为数组");
  }
  if (
    !Number.isInteger(nPeriod) ||
    nPeriod < 1 ||
    !Number.isInteger(nKSmaPeriod) ||
    nKSmaPeriod < 1 ||
    !Number.isInteger(nDSmaPeriod) ||
    nDSmaPeriod < 1
  ) {
    throw new Error("周期参数必须为大于 0 的整数");
  }

  const len = arrClose.length;
  if (len === 0 || arrLow.length !== len || arrHigh.length !== len) {
    throw new Error("输入数组长度不一致或为空");
  }

  const fAlpha = 1 / 3; // 平滑系数

  // 结果数组
  const arrRsv = new Array(len).fill(null);
  const arrK = new Array(len).fill(null);
  const arrD = new Array(len).fill(null);
  const arrJ = new Array(len).fill(null);
  const arrKs = new Array(len).fill(null); // %K 的平滑值
  const arrDs = new Array(len).fill(null); // %D 的平滑值

  // 单调队列用于维护滑动窗口的最小值和最大值
  const minQueue = []; // 维护最小值（递增队列）
  const maxQueue = []; // 维护最大值（递减队列）

  // 滑动窗口相关变量
  let sumRsvForKs = 0; // 用于计算 %K 的平滑移动平均
  let sumKForDs = 0; // 用于计算 %D 的平滑移动平均
  let validRsvCountForKs = 0; // 当前窗口内有效的 RSV 数量
  let validKCountForDs = 0; // 当前窗口内有效的 K 数量

  // 额外队列，用于记录过去 nKSmaPeriod 和 nDSmaPeriod 个有效的 RSV 和 K 值
  const rsvWindow = []; // 滑动窗口内的 RSV 值
  const kWindow = []; // 滑动窗口内的 K 值

  for (let i = 0; i < len; i++) {
    const closePrice = arrClose[i];
    const lowPrice = arrLow[i];
    const highPrice = arrHigh[i];

    // 1. 更新单调队列，维护滑动窗口的最小值和最大值
    while (minQueue.length > 0 && arrLow[minQueue[minQueue.length - 1]] >= lowPrice) {
      minQueue.pop();
    }
    minQueue.push(i);

    while (maxQueue.length > 0 && arrHigh[maxQueue[maxQueue.length - 1]] <= highPrice) {
      maxQueue.pop();
    }
    maxQueue.push(i);

    // 移除超出窗口范围的队列头部元素
    while (minQueue[0] <= i - nPeriod) {
      minQueue.shift();
    }
    while (maxQueue[0] <= i - nPeriod) {
      maxQueue.shift();
    }

    // 当前窗口的最小值和最大值
    const minLow = arrLow[minQueue[0]];
    const maxHigh = arrHigh[maxQueue[0]];

    // 2. 计算 RSV
    let rsv = null;
    if (maxHigh !== minLow) {
      rsv = ((closePrice - minLow) / (maxHigh - minLow)) * 100;
    }
    arrRsv[i] = rsv;

    // 3. 计算 %K
    let k = null;
    if (i > 0 && arrK[i - 1] !== null) {
      k = fAlpha * rsv + (1 - fAlpha) * arrK[i - 1];
    } else {
      k = rsv !== null ? rsv : 50; // 初始值默认设为 50
    }
    arrK[i] = k;

    // 4. 计算 %D
    let d = null;
    if (i > 0 && arrD[i - 1] !== null) {
      d = fAlpha * k + (1 - fAlpha) * arrD[i - 1];
    } else {
      d = k !== null ? k : 50; // 初始值默认设为 50
    }
    arrD[i] = d;

    // 5. 计算 J
    const j = d !== null && k !== null ? 3 * k - 2 * d : null;
    arrJ[i] = j;

    // 6. 计算平滑 %K (Ks)：过去 nKSmaPeriod 个 RSV 的移动平均
    if (rsv !== null) {
      rsvWindow.push(rsv);
      sumRsvForKs += rsv;
      validRsvCountForKs++;
      if (validRsvCountForKs > nKSmaPeriod) {
        sumRsvForKs -= rsvWindow.shift(); // 移除最早的一个 RSV 值
        validRsvCountForKs--;
      }
      arrKs[i] = sumRsvForKs / validRsvCountForKs;
    } else {
      arrKs[i] = null;
    }

    // 7. 计算平滑 %D (Ds)：过去 nDSmaPeriod 个 K 的移动平均
    if (k !== null) {
      kWindow.push(k);
      sumKForDs += k;
      validKCountForDs++;
      if (validKCountForDs > nDSmaPeriod) {
        sumKForDs -= kWindow.shift(); // 移除最早的一个 K 值
        validKCountForDs--;
      }
      arrDs[i] = sumKForDs / validKCountForDs;
    } else {
      arrDs[i] = null;
    }
  }

  return {
    K: arrK,
    D: arrD,
    J: arrJ,
    Ks: arrKs,
    Ds: arrDs,
  };
}
